package com.gitee.luosl.cola.match;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class Pr {

    public static class AwaysTrue implements Predicate<Object> {

        @Override
        public boolean test(Object o) {
            return true;
        }
    }

    private static final Predicate<Object> awaysTrue = new AwaysTrue();

    @SuppressWarnings("unchecked")
    public static <T> Predicate<T> awaysTrue() {
        return (Predicate<T>) awaysTrue;
    }

    public static <T> Predicate<T> eq(T value) {
        return obj -> Objects.equals(obj, value);
    }

    public static <T> Predicate<T> ne(T value) {
        return eq(value).negate();
    }

    public static <T> Predicate<T> instanceOf(Class<? extends T> type) {
        return obj -> obj != null && type.isAssignableFrom(obj.getClass());
    }

    @SafeVarargs
    public static <T> Predicate<T> isIn(T... values) {
        return obj -> new HashSet<>(Arrays.asList(values)).contains(obj);
    }

    @SafeVarargs
    public static <E, T> Predicate<T> isIn(Function<E, T> mapper, E ...values) {
        return obj -> Arrays.stream(values).map(mapper).collect(Collectors.toSet()).contains(obj);
    }

    @SafeVarargs
    public static <T> Predicate<T> isNotIn(T... values) {
        return isIn(values).negate();
    }

    @SafeVarargs
    public static <E, T> Predicate<T> isNotIn(Function<E, T> mapper, E ...values) {
        return isIn(mapper, values).negate();
    }

    public static <T> Predicate<T> isNotNull() {
        return Objects::nonNull;
    }

    public static <T> Predicate<T> isNull() {
        return Objects::isNull;
    }

    public static <T extends Comparable<T>> Predicate<T> gt(T value) {
        return i -> i.compareTo(value) > 0;
    }

    public static <T extends Comparable<T>> Predicate<T> ge(T value) {
        return i -> i.compareTo(value) >= 0;
    }

    public static <T extends Comparable<T>> Predicate<T> lt(T value) {
        return i -> i.compareTo(value) < 0;
    }

    public static <T extends Comparable<T>> Predicate<T> le(T value) {
        return i -> i.compareTo(value) <= 0;
    }

    public static <T extends Comparable<T>> Predicate<T> between(T left, T right) {
        return i -> i.compareTo(left) >= 0 && i.compareTo(right) <= 0;
    }

    public static <T extends Comparable<T>> Predicate<T> notBetween(T left, T right) {
        return between(left, right).negate();
    }



}
